package com.shasselclub.framework.config;

import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import org.springframework.stereotype.Component;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Documentation;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList;

/**
 * @author {@link ServiceModelToSwagger2MapperImpl
 * the original author}
 * @author Yahuan Jin
 * @see ServiceModelToSwagger2MapperImpl
 * @since 2019.08.24
 */
@Component
public class SwaggerOriginalSortedServiceModelToSwagger2MapperImpl extends ServiceModelToSwagger2MapperImpl {

    @Override
    public Swagger mapDocumentation(Documentation from) {
        final Swagger swagger = super.mapDocumentation(from);

        if (Objects.isNull(swagger)) {
            return null;
        }

        Map<String, Path> map__ = mapOriginalSortedApiListings(from.getApiListings());
        if (map__ != null) {
            swagger.setPaths(map__);
        }

        return swagger;
    }

    private Map<String, Path> mapOriginalSortedApiListings(Multimap<String, ApiListing> apiListings) {
        Map<String, Path> paths = new LinkedHashMap<>();
        for (ApiListing each : apiListings.values()) {
            for (ApiDescription api : each.getApis()) {
                paths.put(api.getPath(), mapOperations(api, Optional.fromNullable(paths.get(api.getPath()))));
            }
        }
        return paths;
    }

    private Path mapOperations(ApiDescription api, Optional<Path> existingPath) {
        Path path = existingPath.or(new Path());
        for (springfox.documentation.service.Operation each : nullToEmptyList(api.getOperations())) {
            Operation operation = mapOperation(each);
            path.set(each.getMethod().toString().toLowerCase(), operation);
        }
        return path;
    }
}
